/*
 *  Copyright (c) 2013, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */

package com.facebook.rebound;

import ohos.agp.graphics.Surface;
import ohos.agp.graphics.SurfaceOps;
import ohos.agp.render.Canvas;
import ohos.agp.utils.Rect;
import ohos.agp.window.service.DisplayManager;

import ohos.app.Context;

import ohos.eventhandler.EventHandler;

import ohos.miscservices.timeutility.Time;

import java.util.logging.Handler;

/**
 * OpenHarmony version of the spring looper that uses the most appropriate frame callback mechanism
 * available. It uses OpenHarmony's {@link DisplayManager} when available, otherwise it uses a
 * {@link EventHandler}.
 */
public abstract class OpenHarmonySpringLooperFactory {
    private static Context mContext;

    /**
     * Create an OpenHarmony SpringLooper for the detected OpenHarmony platform.
     * @param context Context
     * @return a SpringLooper
     */
    public static SpringLooper createSpringLooper(Context context) {
        return ChoreographerOpenHarmonySpringLooper.create(context);
    }

    /**
     * The base implementation of the OpenHarmony spring looper, using a {@link Handler} for the
     * frame callbacks.
     */
    private static class LegacyOpenHarmonySpringLooper extends SpringLooper {
        private final EventHandler mHandler;
        private final Runnable mLooperRunnable;
        private boolean mStarted;
        private long mLastTime;

        /**
         * create
         * @return an OpenHarmony spring looper using a new {@link EventHandler} instance
         */
        public static SpringLooper create() {
            return new LegacyOpenHarmonySpringLooper(new EventHandler(EventHandler.current().getEventRunner()));
        }

        public LegacyOpenHarmonySpringLooper(EventHandler handler) {
            mHandler = handler;
            mLooperRunnable = new Runnable() {
                @Override
                public void run() {
                    if (!mStarted || mSpringSystem == null) {
                        return;
                    }
                    long currentTime = Time.getRealActiveTime();
                    mSpringSystem.loop(currentTime - mLastTime);
                    mHandler.postTask(mLooperRunnable);
                }
            };
        }

        @Override
        public void start() {
            if (mStarted) {
                return;
            }
            mStarted = true;
            mLastTime = Time.getRealActiveTime();
            mHandler.removeTask(mLooperRunnable);
            mHandler.postTask(mLooperRunnable);
        }

        @Override
        public void stop() {
            mStarted = false;
            mHandler.removeTask(mLooperRunnable);
        }
    }

    /**
     * The OpenHarmony implementation of the spring looper that uses OpenHarmony's
     * {@link SurfaceOps}
     */
    private static class ChoreographerOpenHarmonySpringLooper extends SpringLooper {
        private SurfaceOps mChoreographer;
        private SurfaceOps.Callback mFrameCallback;
        private boolean mStarted;
        private long mLastTime;

        /**
         * create
         * @param context Context
         * @return a ChoreographerOpenHarmonySpringLooper
         */
        public static ChoreographerOpenHarmonySpringLooper create(Context context) {
            mContext = context;
            return new ChoreographerOpenHarmonySpringLooper(new SurfaceOps() {
                @Override
                public void addCallback(Callback callback) {
                }

                @Override
                public void removeCallback(Callback callback) {
                }

                @Override
                public void setFormat(int i) {
                }

                @Override
                public Canvas lockCanvas() {
                    return null;
                }

                @Override
                public void unlockCanvasAndPost(Canvas canvas) {
                }

                @Override
                public Surface getSurface() {
                    return null;
                }

                @Override
                public void setFixedSize(int i, int i1) {
                }

                @Override
                public void setKeepScreenOn(boolean b) {
                }

                @Override
                public Rect getSurfaceDimension() {
                    return null;
                }
            });
        }

        public ChoreographerOpenHarmonySpringLooper(SurfaceOps choreographer) {
            mChoreographer = choreographer;
            mFrameCallback = new SurfaceOps.Callback() {
                @Override
                public void surfaceCreated(SurfaceOps surfaceOps) {
                    if (!mStarted || mSpringSystem == null) {
                        return;
                    }
                    long currentTime = Time.getRealActiveTime();
                    mSpringSystem.loop(currentTime - mLastTime);
                    mLastTime = currentTime;
                    mChoreographer.addCallback(mFrameCallback);
                }

                @Override
                public void surfaceChanged(SurfaceOps surfaceOps, int i, int i1, int i2) {
                }

                @Override
                public void surfaceDestroyed(SurfaceOps surfaceOps) {
                }
            };
        }

        @Override
        public void start() {
            if (mStarted) {
                return;
            }
            mStarted = true;
            mLastTime = Time.getRealActiveTime();
            mChoreographer.addCallback(mFrameCallback);
            mChoreographer.removeCallback(mFrameCallback);
        }

        @Override
        public void stop() {
            mStarted = false;
            mChoreographer.removeCallback(mFrameCallback);
        }
    }
}
